<!DOCTYPE html>
<html>
<head>
    <title>Physics Spring-Mass System</title>
</head>
<body>
    <canvas id="physicsCanvas" width="800" height="450"></canvas>
    <script>
        const canvas = document.getElementById('physicsCanvas');
        const ctx = canvas.getContext('2d');

        /**
         * Draws a spring as a wavy line between two points.
         * @param {CanvasRenderingContext2D} ctx The canvas rendering context.
         * @param {number} x1 The starting x-coordinate.
         * @param {number} y The y-coordinate (horizontal spring).
         * @param {number} x2 The ending x-coordinate.
         * @param {number} segments The number of half-wave segments.
         * @param {number} amplitude The amplitude of the wave.
         */
        function drawSpring(ctx, x1, y, x2, segments, amplitude) {
            const dx = (x2 - x1) / segments;
            ctx.beginPath();
            ctx.moveTo(x1, y);
            for (let i = 1; i <= segments; i++) {
                // Alternate the wave direction
                const amp = (i % 2 === 0) ? amplitude : -amplitude;
                // Use quadratic curve for a smooth wave
                ctx.quadraticCurveTo(x1 + (i - 0.5) * dx, y + amp, x1 + i * dx, y);
            }
            ctx.stroke();
        }

        // --- Define Drawing Parameters ---
        const centerX = 400;
        const yGround = 300;
        const yCaption = 400;

        // Walls
        const wallLeftX = 50;
        const wallRightX = 750;
        const wallTopY = 120;
        const wallBottomY = yGround;

        // Cylinders
        const cylinderRadius = 40;
        const cylinderGap = 160; // Horizontal distance between centers
        const cylinderLeftCenterX = centerX - cylinderGap / 2;
        const cylinderRightCenterX = centerX + cylinderGap / 2;
        const cylinderCenterY = yGround - cylinderRadius;

        // Block
        const blockHeight = 80;
        const blockWidth = 340;
        const blockY = yGround - 2 * cylinderRadius - blockHeight;
        const blockX = centerX - blockWidth / 2;

        // Springs
        const springY = blockY + blockHeight / 2;
        const springLeftStartX = wallLeftX;
        const springLeftEndX = blockX;
        const springRightStartX = blockX + blockWidth;
        const springRightEndX = wallRightX;
        const springCoils = 3; // The image shows 3 distinct loops
        const springSegments = springCoils * 2 + 1; // Number of half-waves for a good look
        const springAmplitude = 15;

        // Axis
        const axisStartX = 30;
        const axisEndX = 780;
        const arrowSize = 10;

        // --- Start Drawing ---
        ctx.strokeStyle = 'black';
        ctx.lineWidth = 2;
        ctx.font = '24px Arial';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillStyle = 'black';

        // Draw Walls
        ctx.beginPath();
        ctx.moveTo(wallLeftX, wallTopY);
        ctx.lineTo(wallLeftX, wallBottomY);
        ctx.stroke();

        ctx.beginPath();
        ctx.moveTo(wallRightX, wallTopY);
        ctx.lineTo(wallRightX, wallBottomY);
        ctx.stroke();

        // Draw Ground and X-axis
        ctx.beginPath();
        ctx.moveTo(axisStartX, yGround);
        ctx.lineTo(axisEndX, yGround);
        // Arrowhead
        ctx.moveTo(axisEndX, yGround);
        ctx.lineTo(axisEndX - arrowSize, yGround - arrowSize / 2);
        ctx.moveTo(axisEndX, yGround);
        ctx.lineTo(axisEndX - arrowSize, yGround + arrowSize / 2);
        ctx.stroke();

        // Draw Origin Mark
        ctx.beginPath();
        ctx.moveTo(centerX, yGround - 5);
        ctx.lineTo(centerX, yGround + 5);
        ctx.stroke();

        // Draw Cylinders
        ctx.beginPath();
        ctx.arc(cylinderLeftCenterX, cylinderCenterY, cylinderRadius, 0, 2 * Math.PI);
        ctx.stroke();
        ctx.beginPath();
        ctx.arc(cylinderRightCenterX, cylinderCenterY, cylinderRadius, 0, 2 * Math.PI);
        ctx.stroke();

        // Draw Block
        ctx.strokeRect(blockX, blockY, blockWidth, blockHeight);

        // Draw Springs
        drawSpring(ctx, springLeftStartX, springY, springLeftEndX, springSegments, springAmplitude);
        drawSpring(ctx, springRightStartX, springY, springRightEndX, springSegments, springAmplitude);

        // --- Draw Text Labels ---

        // 'k' labels
        ctx.font = 'italic 24px Arial';
        ctx.fillText('k', springLeftStartX + (springLeftEndX - springLeftStartX) / 2, springY - 35);
        ctx.fillText('k', springRightStartX + (springRightEndX - springRightStartX) / 2, springY - 35);

        // 'M' label
        ctx.font = 'italic 32px Arial';
        ctx.fillText('M', centerX, blockY + blockHeight / 2);

        // 'm' labels
        ctx.font = 'italic 24px Arial';
        ctx.fillText('m', cylinderLeftCenterX, cylinderCenterY);
        ctx.fillText('m', cylinderRightCenterX, cylinderCenterY);

        // 'O' label
        ctx.fillText('O', centerX, yGround + 20);

        // 'x' label
        ctx.fillText('x', axisEndX, yGround + 25);

        // Caption
        // Using a font stack that includes Chinese fonts
        ctx.font = '24px "Songti SC", "SimSun", Arial, sans-serif';
        ctx.fillText('力图 7.13.1', centerX, yCaption);

    </script>
</body>
</html>